#!/usr/bin/python

##      CExploitDB.py
#       
#       Copyright 2010 Hugo Teso <hugo.teso@gmail.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import urllib, tarfile, os, string
from lib.libexploit import CIngumaModule

name = "exploitdb"
brief_description = "A Module to fetch and manage exploits from exploit-db.com"
type = "exploit"

globals = ['search', 'xplpath', ]

class CExploitDB(CIngumaModule):
    """Main class with run, help and summary methods"""

    search = ''
    port = ''
    xplpath = ''

    # Exploits will be saved on inguma's directory under data/exploits/
    # unless changed on EXPLOITS_DIR variable
    LOCAL_EXPLOIT_DIR = '/data/exploits/'
    INGUMA_DIR = os.getcwd()
    EXPLOITS_DIR = INGUMA_DIR + LOCAL_EXPLOIT_DIR

    # Local milw0rm exploits list
    EXPLOITS_LIST = EXPLOITS_DIR + 'files.csv'

    # List that will contain exploits list, format:
    #id, file, description, date, author, platform, type, port
    EXPLOITS = []

    def showHelp(self):
        print 
        print "Inguma's Exploit-DB Help"
        print "------------------------"
        print
        print "fetch                        Download exploits from exploit-db"

        if os.path.exists(self.EXPLOITS_DIR):
            print
            print "Manage Exploit-DB commands"
            print "--------------------------"
            print
            print "list                         Show list of local exploits. VERY VERBOSE"
            print "search <string>              Search exploits containing the string"
            print "                             Example: to search for postgre exploits"
            print "                             'search Postgre'"
            print "rport <port>                 Show exploits afecting a remote port"
            print "                             Define the port using command 'rport 22'"
            print "                             Port must be numeric: 22 intead of SSH"
            print "correlate                    Search the DDBB for all exploits matching rport"
            print "                             for all the ports of a scanned machine. Specify"
            print "                             target machine with 'target 192.168.0.1'"
            print "                             Be sure to scan the machine before!"
            print "show                         Show selected exploit source code"
            print "                             Select exploit using xplpath command:"
            print "                             'xplpath path/to/exploit'"
            print

        print "help                         Show this help"
        print "exit                         Exit DDBB"
        print

    def fetchExpl(self):
        # Exploits will be saved on inguma's directory under data/exploits/

        # Move to exploits directory
        try:
        	os.chdir(self.EXPLOITS_DIR)
        except(OSError):
        	os.mkdir(self.EXPLOITS_DIR)
        	os.chdir(self.EXPLOITS_DIR)
        print "Dir: ",self.EXPLOITS_DIR

        # if exploits dir exists, it's considered an update
        if os.path.exists(self.EXPLOITS_DIR):
            print "exploit-db already downloaded, checking for updates"
    
        # Fetching exploits from milw0rm
        page = "http://www.exploit-db.com/archive.tar.bz2"
        print "Downloading ", page
        urllib.urlretrieve(page, "archive.tar.bz2")
    
        # Extract exploits and remove original file
        print "Extracting files..."
        tar = tarfile.open("archive.tar.bz2")
        tar.extractall()
        tar.close()
        os.remove("archive.tar.bz2")
        os.chmod('files.csv', 0644)

        # Let's store actual date
        os.chdir(self.EXPLOITS_DIR)
        self.setDate()

        os.chdir(self.EXPLOITS_DIR)
        print "Operation Complete"

        # Load exploits
        self.loadExploits()

        os.chdir(self.INGUMA_DIR)

    def loadExploits(self):
        """ Parse files.csv and load contents into a list """

        import csv

        #Empty exploits list just in case is an update
        self.EXPLOITS = []

        os.chdir(self.EXPLOITS_DIR)
        file = open('files.csv', 'r')
        reader = csv.reader(file, delimiter=',')

        print "\nLoading exploits..."
        for row in reader:
            self.EXPLOITS.append(row)
        self.EXPLOITS.pop(0)
        print "Exploits loaded:", len(self.EXPLOITS)

        os.chdir(self.INGUMA_DIR)

    def setDate(self):
        """ Stores current date on a file """

        import time
        current_date = time.ctime(time.time())
        f = open('last_date.txt', 'w')
        f.write(current_date)
        f.close()
        print "Exploits successfully downloaded on", current_date

    def readDate(self):
        """ Reads last date of exploits download """

        try:
            os.chdir(self.EXPLOITS_DIR)
        except:
            print "Exploits from exploit-db not yet downloaded"
            return False
        f = open('last_date.txt', 'r').read()
        os.chdir(self.INGUMA_DIR)
        return f

    def listExpl(self):
        """ Prints to stdout the exploits available """

        # Print descriptions of each exploit... verbose
        for exploit in self.EXPLOITS:
            print self.LOCAL_EXPLOIT_DIR + exploit[1] + "\t\t" + exploit[2]

    def searchExpl(self):
        """ Search exploits containing the self.search string """

        # Check if self.search has content
        if self.search:
            print "Searching exploit-db for string:", self.search
            for exploit in self.EXPLOITS:
                if exploit[2].__contains__(self.search):
                    print self.LOCAL_EXPLOIT_DIR + exploit[1] + "\t\t" + exploit[2]
        else:
            print "Must specify a pattern to search for"
            print "Example: search Postgre"

    def correlate(self):
        """ Searches all exploits for each open port of a scanned machine """

        if self.target:
            targetPorts = self.target + '_tcp_ports'
            for port in self.user_data[targetPorts]:
                print "Searching exploit-db for port TCP/" + str(port)
                print
                self.port = str(port)
                self.searchPort()

    def searchPort(self):
        """ Search exploits based on remote port """

        if self.port:
            print "Searching exploit-db for port:", self.port
            for exploit in self.EXPLOITS:
                if exploit[-1] == self.port:
                    print exploit[1] + "\t\t" + exploit[2]
        else:
            print "port variable is empty"
            print "Define the port using for example 'port 22'"

    def showExpl(self):
        """ Prints to stdout selected exploit """

        if self.xplpath:
            f = open(self.xplpath, 'r').read()
            print f
        else:
            print "Select some exploit to show"
            print "Use, for example, 'show ./modules/exploits/milw0rm/rport/22/1787.py'"

    def run(self):
        # Try to read last download date
        last_date = self.readDate()
        if last_date:
            print "Last exploit-db update:", last_date

        # if exploits list exists, load into memory
        if os.path.exists(self.EXPLOITS_LIST):
            print "exploit-db already downloaded, loading on memory"
            self.loadExploits()

        while 1:
            try:
                res = raw_input("LOCXPL> ")
            except KeyboardInterrupt:
                break
            except EOFError:
                break
            except:
                print "raw_input:", sys.exc_info()[1]
            
            words = res.split(" ")

            if len(words) == 1 and words[0] == "":
                continue
            elif words[0].lower() == "help":
                self.showHelp()
            elif words[0].lower() == "quit" or words[0].lower() == "exit":
                break
            elif words[0].lower() == "fetch":
                self.fetchExpl()
            elif words[0].lower() == "list":
                self.listExpl()
            elif words[0].lower() == "search":
                self.search = string.join(words[1:], ' ')
                self.searchExpl()
            elif words[0].lower() == "rport":
                self.port = str(words[1])
                self.searchPort()
            elif words[0].lower() == "correlate":
                self.correlate()
            elif words[0].lower() == "show":
                self.xplpath = str(words[1])
                self.showExpl()
            elif words[0].lower() == 'port':
                self.port = words[1]
                print "New search port: ", self.port
            elif words[0].lower() == 'target':
                self.target = words[1]
                print "Target set for correlation:", self.target
            else:
                print "Unknown command or options '" + str(res) + "'"

        return False

    def printSummary(self):
        print

